package top.cluski.feieprint.service;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import top.cluski.feieprint.api.teable.TeableApi;
import top.cluski.feieprint.api.teable.entity.RecordEntity;
import top.cluski.feieprint.config.FeiEConfig;
import top.cluski.feieprint.domain.dto.FeiEPrintErrorContext;
import top.cluski.feieprint.domain.dto.PrintSettingDTO;
import top.cluski.feieprint.entity.PrintSetting;
import top.cluski.feieprint.entity.PrinterEntity;
import top.cluski.feieprint.exception.FeiEPrintException;
import top.cluski.feieprint.mapper.PrinterMapper;
import top.cluski.feieprint.utils.FeiEPrintUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FeiEPrintService extends ServiceImpl<PrinterMapper, PrinterEntity> {

    @Resource
    FeiEConfig feiEConfig;
    @Resource
    private PrinterMapper printerMapper;
    @Resource
    private TeableApi teableApi;

    public void print(JSONObject jsonObject) {
        log.info("收到参数: {}", jsonObject);
        // 预处理参数
//        feiEPrintDTO.setSandwich(
//                String.join(",", JSONObject.parseObject(feiEPrintDTO.getSandwich(), new TypeReference<List<String>>() {
//                }))
//        );
//        log.info("预处理完参数: {}", feiEPrintDTO);

        HashMap<String, String> renderParams = new HashMap<>();
//        renderParams.put("code", feiEPrintDTO.getCode());
        jsonObject.forEach((key, value) -> renderParams.put(key, value.toString()));
        for (FeiEConfig.MultilineConfig multilineConfig : feiEConfig.getMultiline()) {
            double tmpIdx = 0;
            int tmpLine = 1;
            int startIndex = 0;
            String value;
            value = jsonObject.getString(multilineConfig.getColumn());
            if (StrUtil.isBlank(value)) {
                continue;
            }
            if (value.charAt(0) == '[' && value.endsWith("]")) {
                value = JSONArray.parse(value).stream().map(Object::toString).collect(Collectors.joining(","));
            }
            for (int i = 0; i < value.length(); i++) {
                char word = value.substring(i, i + 1).toCharArray()[0];
                if (word <= 127) {
                    tmpIdx += 0.5;
                } else {
                    tmpIdx += 1;
                }
                if (tmpIdx >= multilineConfig.getSplitCount()) {
                    renderParams.put(multilineConfig.getColumn() + "-" + tmpLine, value.substring(startIndex, i + 1));
                    startIndex = i + 1;
                    tmpIdx = 0;
                    tmpLine++;
                }
            }
            if (StrUtil.isNotBlank(value.substring(startIndex))) {
                renderParams.put(multilineConfig.getColumn() + "-" + tmpLine, value.substring(startIndex));
            }
        }

        log.info("打印参数: {}", renderParams);

        String printTemplate = feiEConfig.getTemplate();
        for (Map.Entry<String, String> entry : renderParams.entrySet()) {
            printTemplate = printTemplate.replace("{{" + entry.getKey() + "}}", entry.getValue());
        }

        // 去除没有替换的
        printTemplate = printTemplate.replaceAll("\\{\\{.+?}}", "");
        log.info("替换后的打印记录参数: {}", printTemplate);

        FeiEPrintUtils.request(jsonObject.getString("name"), printTemplate);
    }

    public void printById(JSONObject jsonObject) {
        Assert.notBlank(jsonObject.getString("recordId"), "record id is blank");
        Assert.notBlank(jsonObject.getString("name"), "name is blank");
        String printerName = jsonObject.getString("name");
        PrinterEntity printerEntity = Optional
                .ofNullable(printerMapper.selectOneByQuery(new QueryWrapper().eq(PrinterEntity::getName, printerName)))
                .orElseThrow(() -> {
                    log.error("不存在该打印机 printerName={}", printerName);
                    return new FeiEPrintException(new FeiEPrintErrorContext(FeiEPrintErrorContext.MainError.PARAM_ERROR,
                            FeiEPrintErrorContext.SubError.PRINTER_NOT_FOUND, printerName), "不存在该打印机");
                });
        RecordEntity record = teableApi.getOneRecord(jsonObject.getString("recordId"));

        String printTemplate = this.getPrintTemplate(printerEntity, record);

        try {
            FeiEPrintUtils.request(printerEntity.getPrinterUser(), printerEntity.getPrinterUkey(),
                    printerEntity.getPrinterSN(),
                    printTemplate);
        } catch (FeiEPrintException e) {
            e.getErrorContext().setPrinterName(printerEntity.getName());
            throw e;
        }
    }

    /**
     * 根据打印机设置，生成模板
     */
    public String generateTemplate(List<PrintSetting> printSettings) {
        String template = printSettings.stream().map(setting -> {
                    Integer rotation = setting.getRotation() != null ? setting.getRotation() : 0;
                    String textContent;

                    // 根据类型决定文本内容
                    if ("manual".equals(setting.getType()) && StrUtil.isNotBlank(setting.getValue())) {
                        // 手动输入类型，直接使用设定的值
                        textContent = setting.getValue();
                    } else {
                        // 字段类型，使用占位符
                        textContent = "{{" + setting.getColumn() + "}}";
                    }

                    if (setting.getMaxLines() == 1) {
                        return StrFormatter.format("""
                                        <TEXT x="{}" y="{}" font="12" w="{}" h="{}" r="{}">{}</TEXT>
                                        """, setting.getLeft(), setting.getTop(), setting.getRatio(), setting.getRatio(),
                                rotation, textContent);
                    } else {
                        StringBuilder sb = new StringBuilder();
                        for (int i = 0; i < setting.getMaxLines(); i++) {
                            String lineContent;
                            if ("manual".equals(setting.getType()) && StrUtil.isNotBlank(setting.getValue())) {
                                // 手动输入类型，多行时都使用相同的值
                                lineContent = setting.getValue();
                            } else {
                                // 字段类型，使用带行号的占位符
                                lineContent = "{{" + setting.getColumn() + "-" + (i + 1) + "}}";
                            }

                            // 根据旋转角度计算换行方向
                            int x, y;
                            if (rotation == 90 || rotation == 270) {
                                // 旋转90度或270度时，换行在X轴方向
                                x = setting.getLeft() + (30 + (setting.getRatio() - 1) * 15) * i;
                                y = setting.getTop();
                            } else {
                                // 正常情况（0度或180度），换行在Y轴方向
                                x = setting.getLeft();
                                y = setting.getTop() + (30 + (setting.getRatio() - 1) * 15) * i;
                            }

                            String tmp = StrFormatter.format("""
                                            <TEXT x="{}" y="{}" font="12" w="{}" h="{}" r="{}">{}</TEXT>
                                            """,
                                    x,
                                    y,
                                    setting.getRatio(),
                                    setting.getRatio(),
                                    rotation,
                                    lineContent);
                            sb.append(tmp);
                        }
                        return sb.toString();
                    }
                })
                .collect(Collectors.joining("\n"));
        template = "<DIRECTION>1</DIRECTION>\n" + template;
        return template;
    }

    public void saveLabelSize(Integer id, Integer width, Integer height) {
        PrinterEntity printerEntity = new PrinterEntity();
        printerEntity.setId(id);
        printerEntity.setLabelWidth(width);
        printerEntity.setLabelHeight(height);
        printerMapper.update(printerEntity);
    }

    public void savePrintSetting(PrintSettingDTO printSettingDTO) {
        PrinterEntity printerEntity = new PrinterEntity();
        printerEntity.setId(printSettingDTO.getPrinterId());
        printerEntity.setPrintSettings(JSONObject.toJSONString(printSettingDTO.getPrintSettingList()));
        printerMapper.update(printerEntity);
    }

    public void testPrint(Integer printerId) {
        PrinterEntity printerEntity = Optional.ofNullable(printerMapper
                        .selectOneByQuery(new QueryWrapper().eq(PrinterEntity::getId, printerId)))
                .orElseThrow(() -> {
                    log.error("暂未找到对应的打印机 printerId={}", printerId);
                    return new FeiEPrintException(new FeiEPrintErrorContext(FeiEPrintErrorContext.MainError.PARAM_ERROR,
                            FeiEPrintErrorContext.SubError.PRINTER_NOT_FOUND, ""), "暂未找到对应的打印机");
                });

        String printTemplate = getPrintTemplate(printerEntity, teableApi.getFirstRecord());
        printTemplate +=
                StrFormatter.format("<SIZE>{},{}</SIZE>",
                        printerEntity.getLabelWidth() * 10, printerEntity.getLabelHeight() * 10);
        try {
            FeiEPrintUtils.request(printerEntity.getPrinterUser(), printerEntity.getPrinterUkey(),
                    printerEntity.getPrinterSN(),
                    printTemplate);
        } catch (FeiEPrintException e) {
            e.getErrorContext().setPrinterName(printerEntity.getName());
            throw e;
        }
    }

    private String getPrintTemplate(@NonNull PrinterEntity printerEntity, @NonNull RecordEntity record) {
        String printSettingsStr = printerEntity.getPrintSettings();
        List<PrintSetting> printSettings = JSONArray.parseArray(printSettingsStr, PrintSetting.class);
        JSONObject fields = record.getFields();

        HashMap<String, String> renderParams = new HashMap<>();
        fields.forEach((key, value) -> renderParams.put(key, value.toString()));

        for (PrintSetting printSetting : printSettings) {
            // 跳过手动输入类型的设置，这些不需要从字段中获取值
            if ("manual".equals(printSetting.getType())) {
                continue;
            }

            double tmpIdx = 0;
            int tmpLine = 1;
            int startIndex = 0;
            String value;
            value = fields.getString(printSetting.getColumn());
            if (StrUtil.isBlank(value)) {
                continue;
            }
            if (value.charAt(0) == '[' && value.endsWith("]")) {
                value = JSONArray.parse(value).stream().map(Object::toString).collect(Collectors.joining(","));
            }
            if (printSetting.getLetterPerLine() != null && printSetting.getLetterPerLine() > 0) {
                for (int i = 0; i < value.length(); i++) {
                    char word = value.substring(i, i + 1).toCharArray()[0];
                    if (word <= 127) {
                        tmpIdx += 0.5;
                    } else {
                        tmpIdx += 1;
                    }
                    if (tmpIdx >= printSetting.getLetterPerLine()) {
                        renderParams.put(printSetting.getColumn() + "-" + tmpLine, value.substring(startIndex, i + 1));
                        startIndex = i + 1;
                        tmpIdx = 0;
                        tmpLine++;
                    }
                }
            }
            if (StrUtil.isNotBlank(value.substring(startIndex))) {
                renderParams.put(printSetting.getColumn() + "-" + tmpLine, value.substring(startIndex));
            }
        }

        log.info("打印参数: {}", renderParams);

        String printTemplate = generateTemplate(printSettings);
        for (Map.Entry<String, String> entry : renderParams.entrySet()) {
            printTemplate = printTemplate.replace("{{" + entry.getKey() + "}}", entry.getValue());
        }
        // 去除没有替换的
        printTemplate = printTemplate.replaceAll("\\{\\{.+?}}", "");
        log.info("替换后的打印记录参数: {}", printTemplate);

        return printTemplate;
    }

    public void copyPrinter(Integer printerId) {
        PrinterEntity printerEntity = this.printerMapper.selectOneById(printerId);
        printerEntity.setId(null);
        printerEntity.setName(printerEntity.getName() + "_副本");
        this.printerMapper.insert(printerEntity);
    }
}
